package com.lee.single.starter.response.handler;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.lee.single.starter.response.PageData;
import com.lee.single.starter.response.Result;
import com.lee.single.starter.response.annotation.DirectOutput;
import com.lee.single.starter.response.constant.ResultCodeConstants;
import com.lee.single.starter.response.exception.AppException;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author lee
 * @since 2019-11-22
 * Controller增强，将返回的内容进行固定封装，并且拦截全局异常
 */
@RestControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {


    @ExceptionHandler(AppException.class)
    public Result appExceptionHandler(AppException e) {

        return Result.error(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {

        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        return Result.error(ResultCodeConstants.ERROR_PARAMS, objectError.getDefaultMessage());
    }

    @ExceptionHandler(Exception.class)
    public Result exceptionHandler(Exception e) {
        e.printStackTrace();
        return new Result(ResultCodeConstants.ERROR_UNKNOWN, "unknown", e.getMessage());
    }

    @Override
    public boolean supports(MethodParameter methodParameter,
                            Class<? extends HttpMessageConverter<?>> aClass) {

        // 如果接口返回的类型本身就是Result或者注解了直接输出，返回false
        return !methodParameter.getGenericParameterType().equals(Result.class)
                && methodParameter.getMethodAnnotation(DirectOutput.class) == null;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {

        // 由于序列化器的原因，禁止直接返回String类型。
        // 如需直接返回String，可用Result直接包装后返回，如:
        // return Result.success("string")

        if (body instanceof IPage) {
            IPage<?> page = (IPage<?>) body;
            PageData pageData = new PageData(page.getCurrent(), page.getTotal(), page.getSize(), page.getRecords());
            return Result.success(pageData);
        } else {
            return Result.success(body);
        }
    }
}
